package com.waves.aspect;

import com.waves.anno.CacheDelete;
import com.waves.anno.CacheGet;
import com.waves.anno.CacheUpdate;
import com.waves.biz.CacheRepository;
import com.waves.util.SpringELParser;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;

/**
 * @Description: 自定义缓存切面
 **/
@Component
@Aspect
@Slf4j
public class CacheAspect {

    @Resource
    private CacheRepository cacheRepository;

    @Around("@annotation(annotation)")
    public Object get(ProceedingJoinPoint pjp, CacheGet annotation) throws Throwable {
        String id = getResult(annotation.id(), pjp);
        String prefix = annotation.prefix();
        Object cache = cacheRepository.getCache(prefix + id);
        if (cache != null) {
            log.info("从缓存中获取数据: {}",cache);
            return cache;
        }
        Object result = pjp.proceed();
        log.info("从数据库中获取数据: {}",result);
        if (result != null) {
            cacheRepository.saveCache(prefix + id, result);
            log.info("添加缓存：{}",result);
        }
        return result;
    }

    /**
     * SpringEL表达式 + 连接点参数列表 -> 运算结果
     */
    private String getResult(String expression, ProceedingJoinPoint pjp) {
        // pjp -> signature -> method -> parameters -> paramNames
        MethodSignature methodSignature = (MethodSignature) pjp.getSignature();
        Method method = methodSignature.getMethod();
        Parameter[] params = method.getParameters();
        String[] paramNames = new String[params.length];
        for (int i = 0; i < params.length; i++) {
            paramNames[i] = params[i].getName();
        }
        // 调用SpringEL解析器，得出表达式结果
        return SpringELParser.getResult(expression, paramNames, pjp.getArgs());

    }

    @Around("@annotation(annotation)")
    public Object update(ProceedingJoinPoint pjp, CacheUpdate annotation) throws Throwable {
        String prefix = annotation.prefix();
        String id = getResult(annotation.id(), pjp);
        Object result = pjp.proceed();
        cacheRepository.saveCache(prefix + id, result);
        log.info("更新缓存：{}",result);
        return result;
    }

    @Around("@annotation(annotation)")
    public Object delete(ProceedingJoinPoint pjp, CacheDelete annotation) throws Throwable {
        String prefix = annotation.prefix();
        String id = getResult(annotation.id(), pjp);
        Object result = pjp.proceed();
        cacheRepository.removeCache(prefix + id);
        log.info("删除缓存key：{}", prefix + id);
        return result;
    }

}
